package com.lizardtech.djvu.codecs
{
	import com.lizardtech.djvu.GPixelReference;
	import com.lizardtech.djvu.GPixmap;
	import com.lizardtech.djvu.IFFChunk;
	import com.lizardtech.djvu.IWCodec;
	import com.lizardtech.djvu.IWMap;
	import com.lizardtech.djvu.ZPCodec;
	import com.lizardtech.djvu.djCodec;

	public class djBG44 extends djCodec
	{
		
		  public static const CRCBfull:int = 5;
		  public static const CRCBhalf:int = 3;	
		  public static const CRCBMode:int = 1;
		  public static const CRCBnone:int = 2;
		  public static const CRCBnormal:int = 4;
		
		  public static const rgb_to_ycc:Array =
		  [
		    new Array(0.304348, 0.608696, 0.086956),
		    new Array(0.463768, -0.405797, -0.057971),
		    new Array(-0.173913, -0.347826, 0.521739)
		  ];
		
		  //~ Instance fields --------------------------------------------------------
		
		
		  private var cbcodec:IWCodec;
		  private var crcodec:IWCodec;
		  private static var ycodec:IWCodec;
		  private var cbmap:IWMap;
		  private var crmap:IWMap;
		  private var ymap:IWMap;
		  private var cbytes:int;
		  private var crcb_delay:int = 10;
		  private var crcb_half:Boolean= false;
		  private static var cserial:int;
		  private var cslice:int;
		  
		public function djBG44()
		{
			super();
		}
		
		public override function decodeChunk(chunk:IFFChunk):void {
			if(ycodec == null)  {
		      cslice   = cserial = 0;
		      ymap     = null;
		    }
		
		    if(chunk.read() != cserial)
		    {
		      throw new Error(
		        "(IWPixmap::decode) Chunk does not bear expected serial number");
		    }
		
		    var nslices:int = cslice + chunk.read();
		
		    if(cserial == 0)
		    {
		      var major:int = chunk.read();
		      var minor:int = chunk.read();
		
		      if((major & 0x7) != 1)
		      {
		        throw new Error(
		          "(IWPixmap::decode) File has been compressed with an incompatible IWCodec");
		      }
		
		      if(minor > 2)
		      {
		        throw new Error(
		          "(IWPixmap::decode) File has been compressed with a more recent IWCodec");
		      }
		
		      var header3size:int = 5;
		
		      if(minor < 2)
		      {
		        header3size = 4;
		      }
		
		      var w:int= (chunk.read() << 8);
		      w |= chunk.read();
		
		      var h:int= (chunk.read() << 8);
		      h |= chunk.read();
		      crcb_delay   = 0;
		      crcb_half    = false;
		
		      var b:int= chunk.read();
		
		      if(minor >= 2)
		      {
		        crcb_delay = 0x7 & b;
		      }
		
		      if(minor >= 2)
		      {
		        crcb_half = ((0x80 & b) == 0);
		      }
		
		      if((major & 0x80) != 0)
		      {
		        crcb_delay = -1;
		      }
		
		      ymap     = new IWMap(w, h);
		      ycodec   = new IWCodec(ymap);
		
		      if(crcb_delay >= 0)
		      {
		        cbmap     = new IWMap(w, h);
		        crmap     = new IWMap(w, h);
		        cbcodec   = new IWCodec(cbmap);
		        crcodec   = new IWCodec(crmap);
		      }
		    }
		
		    var zp:ZPCodec = new ZPCodec(chunk);
		
		    for(var flag:int= 1; (flag != 0) && (cslice < nslices); cslice++)
		    {
		      flag = ycodec.code_slice(zp);
		
		      if((crcodec != null) && (cbcodec != null) && (crcb_delay <= cslice))
		      {
		        flag |= cbcodec.code_slice(zp);
		        flag |= crcodec.code_slice(zp);
		      }
		    }
		
		    cserial++;
		    trace("decoded BG44: " + nslices + " slices.");
		}
	
		public function getPixmap():GPixmap{
		    if(ymap == null)
		    {
		      return null;
		    }
		
		    var w:int= ymap.iw;
		    var h:int= ymap.ih;
		    var pixsep:int= 3;
		    var rowsep:int= w * pixsep;
		    var bytes:Array= new Array(h * rowsep);
		
		    ymap.image(0, bytes, rowsep, pixsep, false);
		
		    if((crmap != null) && (cbmap != null) && (crcb_delay >= 0))
		    {
		      cbmap.image(1, bytes, rowsep, pixsep, crcb_half);
		      crmap.image(2, bytes, rowsep, pixsep, crcb_half);
		    }
		
		    // Convert image to RGB
		    var ppm:GPixmap= new GPixmap(bytes, w, h);
		    var pixel:GPixelReference= ppm.createGPixelReference(0);
		
		    for(var i:int= 0; i < h;)
		    {
		      pixel.setOffset(i++, 0);
		
		      if((crmap != null) && (cbmap != null) && (crcb_delay >= 0))
		      {
		        pixel.YCC_to_RGB(w);
		      }
		      else
		      {
		        for(var x:int= w||0; x-- > 0; pixel.incOffset())
		        {
		          pixel.setGray(127- pixel.getBlue());
		        }
		      }
		    }
		
		    return ppm;
	  }
		
	}
}